#include "c0.h"

#include "conio.h0"
#include "string.h0"
#include "file.h0"
#include "parse.h0"
#include "args.h0"
#include "curses.h0"

#include "c0runtime.h"
#include <assert.h>

#include "c0vm_natives.h"
#include "xalloc.h"

/*** generic wrappers for library functions ***/

/* conio */
void *native_print(void **args) {
    print((char *) args[0]);
    return NULL;
}

void *native_println(void **args) {
    println((char *) args[0]);
    return NULL;
}

void *native_printint(void **args) {
    printint((int) args[0]);
    return NULL;
}

void *native_printbool(void **args) {
    printbool((bool) (int) args[0]);
    return NULL;
}

void *native_printchar(void **args) {
    printchar((char) (int) args[0]);
    return NULL;
}

void *native_readline(void **args) {
    (void) args; /* suppress error */
    return (void *) readline();
}

/* c0vm, v2 */
void *native_error (void **args) {
    error((char *) args[0]);
    return NULL;
}

/* string */
void *native_string_length(void **args) {
    return (void *) string_length((string) args[0]);
}

void *native_string_charat(void **args) {
    return (void *) (int) string_charat((string) args[0], (int) args[1]);
}

void *native_string_join(void **args) {
    return (void *) string_join((char *) args[0], (char *) args[1]);
}

void *native_string_sub(void **args) {
    return (void *) string_sub((string) args[0], (int) args[1], (int) args[2]);
}

void *native_string_equal(void **args) {
    return (void *) string_equal((string) args[0], (string) args[1]);
}

void *native_string_compare(void **args) {
    return (void *) string_compare((string) args[0], (string) args[1]);
}

/* removed in c0vm, v2 */
/*
void *native_char_equal(void **args) {
    return (void *) char_equal((char) (int) args[0], (char) (int) args[1]);
}

void *native_char_compare(void **args) {
    return (void *) char_compare((char) (int) args[0], (char) (int) args[1]);
}
*/

void *native_string_frombool(void **args) {
    return (void *) string_frombool((bool) args[0]);
}

void *native_string_fromint(void **args) {
    return (void *) string_fromint((int) args[0]);
}

void *native_string_fromchar(void **args) {
    return (void *) string_fromchar((char) (int) args[0]);
}

void *native_string_tolower(void **args) {
    return (void *) string_tolower((string) args[0]);
}

void *native_string_to_chararray(void **args) {
    return (void *) string_to_chararray((string) args[0]);
}

void *native_string_from_chararray(void **args) {
    return (void *) string_from_chararray((char *) args[0]);
}

void *native_char_ord(void **args) {
    return (void *) char_ord((char) (int) args[0]);
}

void *native_char_chr(void **args) {
    return (void *) (int) char_chr((int) args[0]);
}

/* file */
void *native_file_read(void **args) {
    return (void *) file_read((string) args[0]);
}

void *native_file_close(void **args) {
    file_close((file_t) args[0]);
    return NULL;
}

void *native_file_eof(void **args) {
    return (void *) file_eof((file_t) args[0]);
}

void *native_file_readline(void **args) {
    return (void *) file_readline((file_t) args[0]);
}

/* parse */
void *native_parse_bool(void **args) {
    return (void *) parse_bool((string) args[0]);
}

void *native_parse_int(void **args) {
    return (void *) parse_int((string) args[0], (int) args[1]);
}

/* args */
void *native_args_flag(void **args) {
    args_flag((string) args[0], (bool *) args[1]);
    return NULL;
}

void *native_args_int(void **args) {
    args_int((string) args[0], (int *) args[1]);
    return NULL;
}

void *native_args_string(void **args) {
    args_string((string) args[0], (string *) args[1]);
    return NULL;
}

void *native_args_parse(void **args) {
    (void) args; /* suppress error */
    return (void *) args_parse();
}

/* abort */
void *native_c0_abort(void **args) {
    c0_abort(c0_string_tocstr((c0_string) args[0]));
    /* we don't free the C string because execution aborts */
    assert(false);
}

/* curses */
void *native_c_initscr(void **args) {
    (void) args; /* suppress error */
    return (void *) c_initscr();
}
void *native_c_cbreak(void **args) {
    (void) args; /* suppress error */
    c_cbreak();
    return NULL;
}
void *native_c_noecho(void **args) {
    (void) args; /* suppress error */
    c_noecho();
    return NULL;
}
void *native_c_keypad(void **args) {
    c_keypad((WINDOW *) args[0], (bool) args[1]);
    return NULL;
}
void *native_c_getch(void **args) {
    (void) args; /* suppress error */
    return (void *) c_getch();
}
void *native_c_addch(void **args) {
    c_addch((int) args[0]);
    return NULL;
}
void *native_c_waddch(void **args) {
    c_waddch((WINDOW *) args[0], (int) args[1]);
    return NULL;
}
void *native_c_waddstr(void **args) {
    c_waddstr((WINDOW *) args[0], (string) args[1]);
    return NULL;
}
void *native_c_wstandout(void **args) {
    c_wstandout((WINDOW *) args[0]);
    return NULL;
}
void *native_c_wstandend(void **args) {
    c_wstandend((WINDOW *) args[0]);
    return NULL;
}
void *native_c_delch(void **args) {
    (void) args; /* suppress error */
    c_delch();
    return NULL;
}
void *native_c_erase(void **args) {
    (void) args; /* suppress error */
    c_erase();
    return NULL;
}
void *native_c_werase(void **args) {
    c_werase((WINDOW *) args[0]);
    return NULL;
}
void *native_c_wclear(void **args) {
    c_wclear((WINDOW *) args[0]);
    return NULL;
}
void *native_c_move(void **args) {
    c_move((int) args[0], (int) args[1]);
    return NULL;
}
void *native_c_wmove(void **args) {
    c_wmove((WINDOW *) args[0], (int) args[1], (int) args[2]);
    return NULL;
}
void *native_c_refresh(void **args) {
    (void) args; /* suppress error */
    c_refresh();
    return NULL;
}
void *native_c_wrefresh(void **args) {
    c_wrefresh((WINDOW *) args[0]);
    return NULL;
}
void *native_c_endwin(void **args) {
    (void) args; /* suppress error */
    return (void *) c_endwin();
}
void *native_c_curs_set(void **args) {
    return (void *) c_curs_set((int) args[0]);
}
void *native_c_subwin(void **args) {
    return (void *) c_subwin((WINDOW *) args[0], (int) args[1], (int) args[2], (int) args[3], (int) args[4]);
}
void *native_cc_wboldon(void **args) {
    cc_wboldon((WINDOW *) args[0]);
    return NULL;
}
void *native_cc_wboldoff(void **args) {
    cc_wboldoff((WINDOW *) args[0]);
    return NULL;
}
void *native_cc_wdimon(void **args) {
    cc_wdimon((WINDOW *) args[0]);
    return NULL;
}
void *native_cc_wdimoff(void **args) {
    cc_wdimoff((WINDOW *) args[0]);
    return NULL;
}
void *native_cc_wreverseon(void **args) {
    cc_wreverseon((WINDOW *) args[0]);
    return NULL;
}
void *native_cc_wreverseoff(void **args) {
    cc_wreverseoff((WINDOW *) args[0]);
    return NULL;
}
void *native_cc_wunderon (void **args) {
    cc_wunderon ((WINDOW *) args[0]);
    return NULL;
}
void *native_cc_wunderoff(void **args) {
    cc_wunderoff((WINDOW *) args[0]);
    return NULL;
}

void *native_cc_highlight(void **args) {
    return (void *) cc_highlight((int) args[0]);
}
void *native_cc_getx(void **args) {
    return (void *) cc_getx((WINDOW *) args[0]);
}
void *native_cc_gety(void **args) {
    return (void *) cc_gety((WINDOW *) args[0]);
}
void *native_cc_getmaxx(void **args) {
    return (void *) cc_getmaxx((WINDOW *) args[0]);
}
void *native_cc_getmaxy(void **args) {
    return (void *) cc_getmaxy((WINDOW *) args[0]);
}
void *native_cc_getbegx(void **args) {
    return (void *) cc_getbegx((WINDOW *) args[0]);
}
void *native_cc_getbegy(void **args) {
    return (void *) cc_getbegy((WINDOW *) args[0]);
}

void *native_cc_key_is_enter(void **args) {
    return (void *) cc_key_is_enter((int) args[0]);
}
void *native_cc_key_is_backspace(void **args) {
    return (void *) cc_key_is_backspace((int) args[0]);
}
void *native_cc_key_is_left(void **args) {
    return (void *) cc_key_is_left((int) args[0]);
}
void *native_cc_key_is_right(void **args) {
    return (void *) cc_key_is_right((int) args[0]);
}
void *native_cc_key_is_up(void **args) {
    return (void *) cc_key_is_up((int) args[0]);
}
void *native_cc_key_is_down(void **args) {
    return (void *) cc_key_is_down((int) args[0]);
}

/*** the native function table ***/

native_fn native_function_table[NATIVE_FUNCTION_COUNT] =
    { /* conio */
      [NATIVE_PRINT]        = native_print,
      [NATIVE_PRINTLN]      = native_println,
      [NATIVE_PRINTINT]     = native_printint,
      [NATIVE_PRINTBOOL]    = native_printbool,
      [NATIVE_PRINTCHAR]    = native_printchar,
      [NATIVE_READLINE]     = native_readline,
      [NATIVE_ERROR]        = native_error,
      /* string */
      [NATIVE_STRING_LENGTH] = native_string_length,
      [NATIVE_STRING_CHARAT] = native_string_charat,
      [NATIVE_STRING_JOIN] = native_string_join,
      [NATIVE_STRING_SUB] = native_string_sub,
      [NATIVE_STRING_EQUAL] = native_string_equal,
      [NATIVE_STRING_COMPARE] = native_string_compare,
      [NATIVE_STRING_FROMBOOL] = native_string_frombool,
      [NATIVE_STRING_FROMINT] = native_string_fromint,
      [NATIVE_STRING_FROMCHAR] = native_string_fromchar,
      [NATIVE_STRING_TOLOWER] = native_string_tolower,
      [NATIVE_STRING_TO_CHARARRAY] = native_string_to_chararray,
      [NATIVE_STRING_FROM_CHARARRAY] = native_string_from_chararray,
      [NATIVE_CHAR_ORD] = native_char_ord,
      [NATIVE_CHAR_CHR] = native_char_chr,
      /* file */
      [NATIVE_FILE_READ] = native_file_read,
      [NATIVE_FILE_CLOSE] = native_file_close,
      [NATIVE_FILE_EOF] = native_file_eof,
      [NATIVE_FILE_READLINE] = native_file_readline,
      /* parse */
      [NATIVE_PARSE_BOOL] = native_parse_bool,
      [NATIVE_PARSE_INT] = native_parse_int,
      /* args */
      [NATIVE_ARGS_FLAG] = native_args_flag,
      [NATIVE_ARGS_INT] = native_args_int,
      [NATIVE_ARGS_STRING] = native_args_string,
      [NATIVE_ARGS_PARSE] = native_args_parse,
      /* abort */
      [NATIVE_C0_ABORT] = native_c0_abort,
      /* curses */
      [NATIVE_C_INITSCR] = native_c_initscr,
      [NATIVE_C_CBREAK] = native_c_cbreak,
      [NATIVE_C_NOECHO] = native_c_noecho,
      [NATIVE_C_KEYPAD] = native_c_keypad,
      [NATIVE_C_GETCH] = native_c_getch,
      [NATIVE_C_ADDCH] = native_c_addch,
      [NATIVE_C_WADDCH] = native_c_waddch,
      [NATIVE_C_WADDSTR] = native_c_waddstr,
      [NATIVE_C_WSTANDOUT] = native_c_wstandout,
      [NATIVE_C_WSTANDEND] = native_c_wstandend,
      [NATIVE_C_DELCH] = native_c_delch,
      [NATIVE_C_ERASE] = native_c_erase,
      [NATIVE_C_WERASE] = native_c_werase,
      [NATIVE_C_WCLEAR] = native_c_wclear,
      [NATIVE_C_MOVE] = native_c_move,
      [NATIVE_C_WMOVE] = native_c_wmove,
      [NATIVE_C_REFRESH] = native_c_refresh,
      [NATIVE_C_WREFRESH] = native_c_wrefresh,
      [NATIVE_C_ENDWIN] = native_c_endwin,
      [NATIVE_C_CURS_SET] = native_c_curs_set,
      [NATIVE_C_SUBWIN] = native_c_subwin,
      [NATIVE_CC_WBOLDON] = native_cc_wboldon,
      [NATIVE_CC_WBOLDOFF] = native_cc_wboldoff,
      [NATIVE_CC_WDIMON] = native_cc_wdimon,
      [NATIVE_CC_WDIMOFF] = native_cc_wdimoff,
      [NATIVE_CC_WREVERSEON] = native_cc_wreverseon,
      [NATIVE_CC_WREVERSEOFF] = native_cc_wreverseoff,
      [NATIVE_CC_WUNDERON]  = native_cc_wunderon ,
      [NATIVE_CC_WUNDEROFF] = native_cc_wunderoff,
      [NATIVE_CC_HIGHLIGHT] = native_cc_highlight,
      [NATIVE_CC_GETX] = native_cc_getx,
      [NATIVE_CC_GETY] = native_cc_gety,
      [NATIVE_CC_GETMAXX] = native_cc_getmaxx,
      [NATIVE_CC_GETMAXY] = native_cc_getmaxy,
      [NATIVE_CC_GETBEGX] = native_cc_getbegx,
      [NATIVE_CC_GETBEGY] = native_cc_getbegy,
      [NATIVE_CC_KEY_IS_ENTER] = native_cc_key_is_enter,
      [NATIVE_CC_KEY_IS_BACKSPACE] = native_cc_key_is_backspace,
      [NATIVE_CC_KEY_IS_LEFT] = native_cc_key_is_left,
      [NATIVE_CC_KEY_IS_RIGHT] = native_cc_key_is_right,
      [NATIVE_CC_KEY_IS_UP] = native_cc_key_is_up,
      [NATIVE_CC_KEY_IS_DOWN] = native_cc_key_is_down,
    };
